/*
 Trabajo Practico 3 Ejercicio 4
 Servidor TCP
 Segunda Entrega

 - Integrantes:
        - Barrera, Lourdes              DNI: 33306634
        - Martinez, Guillermo   		DNI: 34510461
        - Reyes, Leandro                DNI: 34213699
        - Rodriguez, Lucas              DNI: 34265017
*/

#include "../defines.c"

// Handler que finaliza servidor
void finalizar(int);

// Funcion error
void error(char*);

// Sockets
int sock_descriptor, sock_descriptor_cli;

int main()
{
	char timest[TAM_MSJ];              			// dd/mm/yy hh:mm:ss
	char timest_cliente[TAM_MSJ];      			// dd/mm/yy hh:mm:ss
	struct sockaddr_in socketdir;	       		// Dir socket servidor
	struct sockaddr_in socketdir_cliente; 		// Dir socket cliente
	int addrlen, val=1;							// Tamaño de dirección
	pid_t pid;
    int puerto;
	FILE* arch;
	
	if((arch = fopen("config/server_cfg","rt")) == NULL)
	{
		printf("No se puede leer configuración\n");
		exit(1);
	}
	
	fscanf(arch,"PUERTO = %d",&puerto);
	
	// Para hacer demonio
	if ((pid = fork()) < 0)
		exit(EXIT_FAILURE);
		
	if (pid > 0)
		exit(EXIT_SUCCESS);
		
	umask(0);

	// Manejar la finalizacion
	signal(SIGUSR1,finalizar);
	signal(SIGINT,finalizar);
	signal(SIGTERM,finalizar);

	// Obtenemos un socket tipo internet
	if((sock_descriptor = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		error("Error en creación socket");

	// Información del host
	socketdir.sin_family = AF_INET;
	socketdir.sin_addr.s_addr = INADDR_ANY;
	socketdir.sin_port = htons(puerto);

	// Eliminamos tiempo de espera luego de uso del socket
	if(setsockopt(sock_descriptor, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(int)) == -1)
		error("Error en socket reuse");
		
	// Bind
	if(bind(sock_descriptor, (struct sockaddr *) &socketdir, sizeof(socketdir)) == -1)
		error("");

	// Escuchar en el socket
	if(listen(sock_descriptor, 5) == -1)
		error("Error en listen");

	while(1)
	{
		// Esperar que algun cliente solicite servicio
		if((sock_descriptor_cli = accept(sock_descriptor, (struct sockaddr *) &socketdir_cliente, (socklen_t *) &addrlen)) == -1)
			error("Error en accept");

		// Recibir msj del cliente
		if(recv(sock_descriptor_cli, timest_cliente, sizeof(timest_cliente), 0) == -1)
			error("Error en recv");
		
		// Time servidor
		sleep(1);
		timestamp(timest);

		// Calcular diferencia
		resta_timestamp(timest, timest_cliente);

		// Enviar respuesta del servicio
		if(send(sock_descriptor_cli, timest, sizeof(timest), 0) == -1)
			error("Error en send");
			
		// Cerrar socket
		close(sock_descriptor_cli);
	}
}

void finalizar(int signal)
{
	close(sock_descriptor);
	close(sock_descriptor_cli);
	exit(0);
}

void error(char *e)
{
	// Error Log
	FILE* arch = fopen("error_log","wt");
	fprintf(arch,"%s\n",e);
	
	close(sock_descriptor);
	close(sock_descriptor_cli);
	fcloseall();
	exit(1);
}
